package com.hqd.jjvm.rtda;

import com.hqd.jjvm.rtda.heap.JClass;
import com.hqd.jjvm.rtda.heap.JMethod;
import com.hqd.jjvm.rtda.obj.JObject;
import com.hqd.jjvm.rtda.slot.RefSlot;
import com.hqd.jjvm.rtda.slot.Slot;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.util.concurrent.atomic.AtomicInteger;

@Getter
@Setter
@AllArgsConstructor
public class StackFrame {
    private LocalVars localVars;
    private OperandStack operandStack;
    private JMethod jMethod;
    private JClass jClass;
    private AtomicInteger returnAddress;

    public StackFrame(OperandStack stack, JMethod jMethod) {
        this.operandStack = stack;
        this.localVars = new LocalVars(jMethod.getMaxLocals());
        this.jMethod = jMethod;
        this.jClass = jMethod.getJClass();
        this.returnAddress = new AtomicInteger(0);
    }

    public StackFrame(JMethod jMethod) {
        this.operandStack = new OperandStack(jMethod.getMaxStack());
        this.localVars = new LocalVars(jMethod.getMaxLocals());
        this.jClass = jMethod.getJClass();
        this.jMethod = jMethod;
        this.returnAddress = new AtomicInteger(0);
    }

    public Slot pop() {
        return operandStack.pop();
    }

    public void push(Slot slot) {
        operandStack.push(slot);
    }

    public void pushRef(JObject jObject) {
        operandStack.push(new RefSlot(jObject));
    }

    public Slot getSlotByIndex(int index) {
        return localVars.getSlots()[index];
    }

    public Object getLocalVarsVal(int index) {
        return localVars.getSlots()[index];
    }

    public int getLocalVarsIntVal(int index) {
        return localVars.getIntVal(index);
    }

    public void setLocalVarsIntVal(int index, int val) {
        localVars.setIntVal(index, val);
    }

    public Integer popOperandStackIntVal() {
        return operandStack.popInt();
    }

    public Long popOperandStackLongVal() {
        return operandStack.popLong();
    }

    public Float popOperandStackFloatVal() {
        return operandStack.popFloat();
    }

    public Double popOperandStackDoubleVal() {
        return operandStack.popDouble();
    }

    public JObject popOperandStackRefVal() {
        return operandStack.popRef();
    }

}